#pragma once
#include "Reactor_pool.hpp"
#include "Connection.hpp"
#include "Socket.hpp"
#include "Ioservice.hpp"
#include "Parse.hpp"
#include "Eventfd.hpp"
#include <memory>

#define SINGAL 1
#define ACQUIRE_SOCKFD 1

class Reactor_pool;
using namespace SocketModule;
class Listener : public Connection
{
public:
    Listener(uint16_t port)
        : _listen_sockfd_ptr(std::make_unique<TcpSocket>()), _port(port)
    {
        _listen_sockfd_ptr->BuildTcpSocketMethod(port);
        SetSockfd(_listen_sockfd_ptr->Fd()); // 设置fd进入Connection
        SetEvents(EPOLLIN | EPOLLET);

        parse.RegisterCal([&](const request &req)
                          { return cal.Execute(req); });
    }
    // 在成功能够插入listener模块之后，编写Recver和io模块  ->io模块(处理inbuffer非阻塞循环读(协议+处理) ，outbuffer(写关心按需设置))
    virtual void Recver() override
    {
        /*listen套接字循环读取缓冲区,直到缓冲区没有数据*/
        while (true) /*这里sockfd内部封装的accept方法我们要把错误宏带出来进行分析，因为宏中存放的是最清晰的错误信息*/
        {
            InetAddr peer;
            int aerrno = 0;
            // accept 非阻塞的时候，就是IO，我们就向处理read一样，处理accept
            int sockfd = _listen_sockfd_ptr->Accepter(&peer, &aerrno);
            if (sockfd > 0)
            {
                // 说明正确accept了
                auto coon = std::make_shared<ioservice>(sockfd);
                LOG(LogLevel::INFO) << "用户信息: " << peer.Addr();
                // 设置进Reactor中,并且将协议的处理方法注册给IOservice模块

                coon->RegisterFunc([&](std::string packge)
                                   { return parse.HandlerBuffer(packge); }); // 将处理的接口注册给ioservice

                // GetOwner()->InsertConnection(coon);从此以后主Reactor不再对新连接进行关心
                GetOwner()->GetOwner()->GetQueue().push(sockfd); // 将文件描述符push到队列中
                Listener::_accept_count++;
                // 每次获得整数倍个ACQUIRE_SOCKFD个连接，负载均衡的通知各个子Reactor
                if (Listener::_accept_count / ACQUIRE_SOCKFD == 0)
                {
                    int index = SelectThread();
                    std::cout << "挑选的是: " << index + 2 << "号线程" << std::endl;
                    /*挑选好了，向对应的Eventfd中写入 */
                    auto Event = GetOwner()->GetOwner()->GetEventfdMap()[index];
                    auto EventfdPtr = std::static_pointer_cast<Eventfd>(Event);
                    EventfdPtr->Write(SINGAL); // 此时向指定Event写入，对应的Reactor会调用Recver()
                }
            }
            else
            {
                // sockfd<0,根据错误信息判断
                if (aerrno == EAGAIN | aerrno == EWOULDBLOCK)
                {
                    LOG(LogLevel::INFO) << "底层数据读取完毕";
                    break;
                }
                if (aerrno == EINTR)
                {
                    LOG(LogLevel::INFO) << "信号中断";
                    return;
                }
                else
                {
                    LOG(LogLevel::WARNING) << "accetper error ... Ignore"; // 其他的忽略，反正也没有建立连接
                    break;
                }
            }
        }
    }

    int SelectThread()
    {
        srand(time(nullptr));

        int index = rand() % (GetOwner()->GetOwner()->GetNum() - 2); // index范围 0-8,总共9个子Reactor，一个主Reactor
        return index;
    }

    virtual void Sender() override
    {
    }

    virtual void Excepter() override
    {
    }

    virtual ~Listener() override
    {
        _listen_sockfd_ptr->Close(); // 关闭listen套接字后析构  //析构函数名字相同，所以要设置成虚函数，否则会造成fd泄露
    }

    void Close()
    {
        if (_sockfd > 0)
            ::close(_sockfd);
    }

private:
    std::unique_ptr<Socket> _listen_sockfd_ptr;
    u_int16_t _port;

    Calculator cal;
    Parse parse;
    static int _accept_count;
};
int Listener::_accept_count = 0;